home *** CD-ROM | disk | FTP | other *** search
- /*
- * gzip.c for MacGzip 1.0
- * SPDsoft, August 22, 1995
- * very little to do with original gzip.c (gzip.c.cln in this distribution)
- */
-
- /* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
- * Copyright (C) 1992-1993 Jean-loup Gailly
- * The unzip code was written and put in the public domain by Mark Adler.
- * Portions of the lzw code are derived from the public domain 'compress'
- * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
- * Ken Turkowski, Dave Mack and Peter Jannesen.
- *
- */
-
-
- #ifdef RCSID
- static char rcsid[] = "$Id: gzip.c,v 0.24 1993/06/24 10:52:07 jloup Exp $";
- #endif
-
- #include <signal.h>
- #include <errno.h>
- #include <stdlib.h>
-
- #include <setjmp.h>
-
- #include "tailor.h"
-
- #include "MacIO.h"
- #include "FileTypes.h"
- #include "Prefs.h"
- #include "Globals.h"
- #include "GzErrors.h"
- #include "GzPStrings.h"
-
- #include "gzip.h"
- #include "lzw.h"
- #include "revision.h"
-
-
- typedef RETSIGTYPE (*sig_type) OF((int));
-
-
-
- #ifndef MAX_PATH_LEN
- # define MAX_PATH_LEN 255 /* max pathname length */
- #endif
-
-
- #define PART_SEP "."
-
- /* global buffers */
-
- DECLARE(uch, inbuf, INBUFSIZ +INBUF_EXTRA);
- DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
- DECLARE(ush, d_buf, DIST_BUFSIZE);
- DECLARE(uch, window, 2L*WSIZE);
- #ifndef MAXSEG_64K
- DECLARE(ush, tab_prefix, 1L<<BITS);
- #else
- DECLARE(ush, tab_prefix0, 1L<<(BITS-1));
- DECLARE(ush, tab_prefix1, 1L<<(BITS-1));
- #endif
-
- /* local variables */
-
- int macbinary = 0;
- int ascii = 0; /* convert end-of-lines to local OS conventions */
- int to_stdout = 0; /* output to stdout (-c) */
- int decompress = 0; /* decompress (-d) */
- int force = 0; /* don't ask questions, compress links (-f) */
- int no_name = -1; /* don't save or restore the original file name */
- int no_time = -1; /* don't save or restore the original file time */
- int list = 0; /* list the file contents (-l) */
- int verbose = 0; /* be verbose (-v) */
- int quiet = 0; /* be very quiet (-q) */
- int test = 0; /* test .gz file integrity */
- char *progname ="gzip"; /* program name */
- int maxbits = BITS; /* max bits per code for LZW */
- int method = DEFLATED; /* compression method */
- int level = 6; /* compression level */
- int exit_code = OK; /* program exit code */
- int save_orig_name; /* set if original name must be saved */
- int last_member; /* set for .zip and .Z files */
- int part_nb; /* number of parts in .gz file */
- long time_stamp; /* original time stamp (modification time) */
- long ifile_size; /* input file size, -1 for devices (debug only) */
- char z_suffix[MAX_SUFFIX+1]; /* default suffix (can be set with --suffix) */
- int z_len; /* strlen(z_suffix) */
-
- long bytes_in; /* number of input bytes */
- long bytes_out; /* number of output bytes */
- long total_in = 0; /* input bytes for all files */
- long total_out = 0; /* output bytes for all files */
- char ifname[MAX_PATH_LEN]; /* input file name */
- char ofname[MAX_PATH_LEN]; /* output file name */
- int remove_ofname = 0; /* remove output file on error */
- struct stat istat; /* status for input file */
- int ifd; /* input file descriptor */
- int ofd; /* output file descriptor */
- unsigned insize; /* valid bytes in inbuf */
- unsigned inptr; /* index of next byte to be processed in inbuf */
- unsigned outcnt; /* bytes in output buffer */
-
- jmp_buf env; /* for setjmp (do_exit) */
-
- FSSpec ifs,
- ofs;
-
- /* local functions */
-
- local void treat_file( FSSpec *fs );
- local int create_outfile OF((void));
- local char *get_suffix OF((char *name));
- local int get_istat( FSSpec *ifs, struct stat *sbuf);
- local int make_ofname OF((void));
- local void shorten_name OF((char *name));
- local int get_method OF((int in));
- local int check_ofname OF((void));
- local void copy_stat OF((struct stat *ifstat));
- local void do_exit OF((int exitcode));
- int (*work) OF((int infile, int outfile)) = zip; /* function to call */
- local void reset_times (FSSpec *fs, struct stat *statb);
-
- local Boolean init_globals( FSSpec *fs );
- OSErr PromptGZIPFile( FSSpec *fs, Str255 prompt );
- OSErr MakeOFSSpec( FSSpec *fs , Str255 prompt );
-
- #define strequ(s1, s2) (strcmp((s1),(s2)) == 0)
-
- int gzip ( FSSpec *fs );
-
-
- /* ======================================================================== */
- int gzip ( FSSpec *fs )
- {
- int file_count; /* number of files to precess */
- int proglen; /* length of progname */
-
-
- if ( setjmp(env) != 0)
- {
- /* this is executed upon process error */
-
- return ERROR;
- }
-
-
-
- proglen = 4;
-
- if (get_istat(fs, &istat) != OK) return ERROR;
- if (init_globals( fs )) return ERROR;
-
- ifs = *fs;
- ofs = *fs;
-
- /* By default, save name and timestamp on compression but do not
- * restore them on decompression.
- */
- if (no_time < 0) no_time = decompress;
- if (no_name < 0) no_name = decompress;
-
- file_count = 1;
-
- if ((z_len == 0 && !decompress) || z_len > MAX_SUFFIX)
- {
- /* this should never happend (suffix is tested in PrefsDlg.c) */
-
- DoError(INPUT_ERR, WARN_ERR, "%s: incorrect suffix '%s'", progname, z_suffix);
- do_exit(ERROR);
- }
-
- /* if (do_lzw && !decompress) work = lzw; *//* not supported in gzip 1.2.4 */
-
- /*
- * Allocate all global buffers (for DYN_ALLOC option)
- */
-
- ALLOC(uch, inbuf, INBUFSIZ +INBUF_EXTRA);
- ALLOC(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
- ALLOC(ush, d_buf, DIST_BUFSIZE);
- ALLOC(uch, window, 2L*WSIZE);
- #ifndef MAXSEG_64K
- ALLOC(ush, tab_prefix, 1L<<BITS);
- #else
- ALLOC(ush, tab_prefix0, 1L<<(BITS-1));
- ALLOC(ush, tab_prefix1, 1L<<(BITS-1));
- #endif
-
- /* And get to work */
-
- treat_file( &ifs );
-
-
- /* do_list(-1, -1); *//* print totals */
-
- do_exit(exit_code);
- return exit_code; /* just to avoid lint warning */
- }
-
-
- /* ========================================================================
- * Compress or decompress the given file
- */
- local void treat_file( FSSpec *fs )
- {
- int imode;
-
-
-
- if ( !decompress && macbinary )
- ifile_size = istat.st_mbsize;
- else
- ifile_size = istat.st_size;
-
- time_stamp = no_time ? 0 : istat.st_mtime;
-
- /* Generate output file name. For -r and (-t or -l), skip files
- * without a valid gzip suffix (check done in make_ofname).
- */
-
- if (make_ofname() != OK) return;
-
- /* Here we don't have the true output fname (when decompress)
- * just the iname without the suffix. We will wait to 'create_outfile'
- */
-
- if ( decompress )
- {
- imode = OM_RDONLY | OM_BINARY;
- }
- else
- {
- if ( macbinary == 1) imode = OM_RDONLY | OM_MACBINARY;
- else if ( ascii == 1) imode = OM_RDONLY | OM_TEXT;
- else imode = OM_RDONLY | OM_BINARY;
- }
-
- ifd = fs_open( fs, imode );
-
- if (ifd == -1)
- {
- DoError(STDC_ERR, WARN_ERR, "%s: %s:", progname, ifname);
- exit_code = ERROR;
- return;
- }
-
- clear_bufs(); /* clear input and output buffers */
- part_nb = 0;
-
- if (decompress)
- {
- method = get_method(ifd); /* updates ofname if original given */
- if (method < 0)
- {
- close(ifd);
- return; /* error message already emitted */
- }
- }
- /*
- * Here we have enough info to set decompress flags.
- *
- * even if we are trying MacBinary, we should try to
- * map the file, since MB translation can fail, if
- * the file is not really a MB gziped file, and then we'll
- * have to switch to the default mode.
- */
-
- if (create_outfile() != OK) return;
-
-
- /* Keep the name even if not truncated except with --no-name: */
- if (!save_orig_name) save_orig_name = !no_name;
-
-
- /*
- * Open progress window...
- */
-
- gApp.Working = TRUE;
- SetMMString( "g%szip (%s) %s", decompress ? "un" : "" , macbinary ? "MBII" : ( ascii ? "ASCII" : "bin" ), ofname );
- InitMovableModal( ifile_size, &fd_table[ifd].pos );
- DoSystemTask();
-
- /* Actually do the compression/decompression. Loop over zipped members.
- */
- for (;;)
- {
- if ((*work)(ifd, ofd) != OK)
- {
- method = -1; /* force cleanup */
- break;
- }
-
- if (!decompress || last_member || inptr == insize) break;
- /* end of file */
-
- method = get_method(ifd);
- if (method < 0) break; /* error message already emitted */
- bytes_out = 0; /* required for length check */
- }
-
- close(ifd);
-
- DoSystemTask();
-
- if ( close(ofd) )
- {
- write_error();
- }
-
- if (method == -1)
- {
- fs_unlink ( &ofs );
- return;
- }
-
- copy_stat(&istat);
- }
-
- /* ========================================================================
- * Create the output file. Return OK or ERROR.
- * Try several times if necessary to avoid truncating the z_suffix. For
- * example, do not create a compressed file of name "1234567890123."
- * Sets save_orig_name to true if the file name has been truncated.
- * IN assertions: the input file has already been open (ifd is set) and
- * ofname has already been updated if there was an original name.
- * OUT assertions: ifd and ofd are closed in case of error.
- */
-
- /*
- * MacGzip:
- *
- * if gApp.Prompt we must sfgetfile with ofname,
- * anyway, if we are decompressing a MB file we only will know
- * its name at the moment of create it.
- *
- */
-
- local int create_outfile()
- {
- int flags;
-
-
- if (check_ofname() != OK)
- {
- close(ifd);
- return ERROR;
- }
-
-
- /* set flags */
-
- if ( decompress )
- {
- gSufMap.Found = FALSE;
- ascii = 0;
- macbinary = 0;
-
- /* even if we are trying mb, we must check suffix mapping */
-
- macbinary = gPrefs.Decompress.TryMB ? 1 : 0;
-
- if ( gPrefs.Decompress.Mode == kDeco_MASCII )
- {
- gSufMap.Binary = FALSE;
- gSufMap.MacFile = FALSE;
- }
- else
- {
- gSufMap.Binary = TRUE;
- gSufMap.MacFile = FALSE;
- }
-
- if (( gPrefs.Decompress.Keys ) && ( gApp.KeysMode != 0 ))
- {
- switch ( gApp.KeysMode )
- {
- case kAppKeyASCII:
- gSufMap.Binary = FALSE;
- gSufMap.MacFile = FALSE;
- macbinary = 0;
- break;
- case kAppKeyBin:
- gSufMap.Binary = TRUE;
- gSufMap.MacFile = FALSE;
- macbinary = 0;
- break;
- case kAppKeyMBin:
- gSufMap.Binary = TRUE;
- gSufMap.MacFile = TRUE;
- macbinary = 1;
- break;
- default:
- DoError(PROG_ERR,WARN_ERR,"Mala suerte, error del programador");
- break;
- }
- }
- else
- {
- if ( gPrefs.Decompress.IC )
- {
- ResolveFileType( &ofs, nil, &gSufMap, kRFTDownload | kRFTFromSpec | kRFTIC );
- }
- else if ( gPrefs.Decompress.Fetch )
- {
- ResolveFileType( &ofs, nil, &gSufMap, kRFTDownload | kRFTFromSpec | kRFTFetch );
- }
- }
-
- if ( ! gSufMap.Found )
- {
- if ( gSufMap.Binary )
- {
- gSufMap.Type = gPrefs.Decompress.BinType;
- gSufMap.Creator = gPrefs.Decompress.BinCreator;
- }
- else
- {
- gSufMap.Type = 'TEXT';
- gSufMap.Creator = gPrefs.Decompress.TextCreator;
- }
- }
-
- ascii = gSufMap.Binary ? 0 : 1;
-
-
- flags = OM_WRONLY | ( ascii ? OM_TEXT : OM_BINARY );
- if ( macbinary ) flags |= OM_MACBINARY;
-
- DefCreator = gSufMap.Creator;
- DefType = gSufMap.Type;
-
- }
- else /* compress */
- {
- flags = OM_WRONLY | OM_BINARY;
-
- DefCreator = 'Gzip'; /* externals in MacIO.c */
- DefType = 'Gzip';
- }
-
-
-
-
- /* Create the output file */
- remove_ofname = 1;
- ofd = fs_open( &ofs, flags );
- if (ofd == -1)
- {
- DoError(STDC_ERR, WARN_ERR, "Can't open %s", ofname );
-
- close(ifd);
- exit_code = ERROR;
- return ERROR;
- }
-
-
- return OK;
- }
-
- /***************************************************************************
- * Return a pointer to the 'z' suffix of a file name, or NULL. For all
- * systems, ".gz", ".z", ".Z", ".taz", ".tgz", "-gz", "-z" and "_z" are
- * accepted suffixes, in addition to the value of the --suffix option.
- * ".tgz" is a useful convention for tar.z files on systems limited
- * to 3 characters extensions. On such systems, ".?z" and ".??z" are
- * also accepted suffixes. For Unix, we do not want to accept any
- * .??z suffix as indicating a compressed file; some people use .xyz
- * to denote volume data.
- * On systems allowing multiple versions of the same file (such as VMS),
- * this function removes any version suffix in the given name.
- */
- local char *get_suffix(name)
- char *name;
- {
- int nlen, slen;
- char suffix[MAX_SUFFIX+3]; /* last chars of name, forced to lower case */
- static char *known_suffixes[] =
- {z_suffix, ".gz", ".z", ".taz", ".tgz", "-gz", "-z", "_z",
- #ifdef MAX_EXT_CHARS
- "z",
- #endif
- NULL};
- char **suf = known_suffixes;
-
- if (strequ(z_suffix, "z")) suf++; /* check long suffixes first */
-
- #ifdef SUFFIX_SEP
- /* strip a version number from the file name */
- {
- char *v = strrchr(name, SUFFIX_SEP);
- if (v != NULL) *v = '\0';
- }
- #endif
- nlen = strlen(name);
- if (nlen <= MAX_SUFFIX+2) {
- strcpy(suffix, name);
- } else {
- strcpy(suffix, name+nlen-MAX_SUFFIX-2);
- }
- strlwr(suffix);
- slen = strlen(suffix);
- do {
- int s = strlen(*suf);
- if (slen > s && suffix[slen-s-1] != PATH_SEP
- && strequ(suffix + slen - s, *suf)) {
- return name+nlen-s;
- }
- } while (*++suf != NULL);
-
- return NULL;
- }
-
-
- /***************************************************************************
- * Set ifname to the input file name (with a suffix appended if necessary)
- * and istat to its stats. For decompression, if no file exists with the
- * original name, try adding successively z_suffix, .gz, .z, -z and .Z.
- * For MSDOS, we try only z_suffix and z.
- * Return OK or ERROR.
- */
-
- /*
- * For MacOS:
- *
- * Set ifname to the input file name
- *
- * - we dont need to append anything
- * - no stat
- */
-
- local int get_istat( FSSpec *ifs, struct stat *sbuf)
- {
- Str255ToCStr( ifname, ifs->name );
-
- errno = 0;
-
- if ( fs_stat(ifs, sbuf) == 0)
- return OK;
- else
- {
- exit_code = ERROR;
- return ERROR;
- }
- }
-
- /***************************************************************************
- * Generate ofname given ifname. Return OK, or WARNING if file must be skipped.
- * Sets save_orig_name to true if the file name has been truncated.
- */
- local int make_ofname()
- {
- char *suff; /* ofname z suffix */
-
- strcpy(ofname, ifname);
- /* strip a version number if any and get the gzip suffix if present: */
- suff = get_suffix(ofname);
-
- if (decompress)
- {
- if (suff == NULL)
- {
- WARN((stderr,"%s: %s: unknown suffix -- ignored", progname, ifname));
- return WARNING;
- }
-
- /* Make a special case for .tgz and .taz: */
- strlwr(suff);
- if (strequ(suff, ".tgz") || strequ(suff, ".taz"))
- {
- strcpy(suff, ".tar");
- }
- else
- {
- *suff = '\0'; /* strip the z suffix */
- }
- /* ofname might be changed later if infile contains an original name */
- }
- else /* compress */
- if (suff != NULL)
- {
- DoStdIO(stderr, "%s: %s already has %s suffix -- unchanged",
- progname, ifname, suff);
-
- if (exit_code == OK) exit_code = WARNING;
- return WARNING;
- }
- else
- {
- save_orig_name = 0;
- strcat(ofname, z_suffix);
-
- if ( macbinary == 1 )
- strcat(ifname, ".bin");
-
- } /* decompress ? */
-
- return OK;
- }
-
-
- /* ========================================================================
- * Check the magic number of the input file and update ofname if an
- * original name was given and to_stdout is not set.
- * Return the compression method, -1 for error, -2 for warning.
- * Set inptr to the offset of the next byte to be processed.
- * Updates time_stamp if there is one and --no-time is not used.
- * This function may be called repeatedly for an input file consisting
- * of several contiguous gzip'ed members.
- * IN assertions: there is at least one remaining compressed member.
- * If the member is a zip file, it must be the only one.
- */
- local int get_method(int in) /* input file descriptor */
- {
- uch flags; /* compression flags */
- char magic[2]; /* magic header */
- ulg stamp; /* time stamp */
-
-
- magic[0] = (char)get_byte();
- magic[1] = (char)get_byte();
-
- method = -1; /* unknown yet */
- part_nb++; /* number of parts in gzip file */
- header_bytes = 0;
- last_member = RECORD_IO;
- /* assume multiple members in gzip file except for record oriented I/O */
-
- if (memcmp(magic, GZIP_MAGIC, 2) == 0
- || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0)
- {
- method = (int)get_byte();
- if (method != DEFLATED)
- {
- DoError(INPUT_ERR,WARN_ERR,
- "%s: %s: unknown method %d -- get newer version of gzip",
- progname, ifname, method);
- exit_code = ERROR;
- return -1;
- }
-
- work = unzip;
- flags = (uch)get_byte();
-
- if ((flags & ENCRYPTED) != 0)
- {
- DoError(INPUT_ERR,WARN_ERR,
- "%s: %s is encrypted -- get newer version of gzip",
- progname, ifname);
- exit_code = ERROR;
- return -1;
- }
-
- if ((flags & CONTINUATION) != 0)
- {
- DoError(INPUT_ERR,WARN_ERR,
- "%s: %s is a a multi-part gzip file -- get newer version of gzip",
- progname, ifname);
- exit_code = ERROR;
- if (force <= 1) return -1;
- }
-
- if ((flags & RESERVED) != 0)
- {
- DoError(INPUT_ERR,WARN_ERR,
- "%s: %s has flags 0x%x -- get newer version of gzip",
- progname, ifname, flags);
- exit_code = ERROR;
- if (force <= 1) return -1;
- }
-
- stamp = (ulg)get_byte();
- stamp |= ((ulg)get_byte()) << 8;
- stamp |= ((ulg)get_byte()) << 16;
- stamp |= ((ulg)get_byte()) << 24;
-
- if (stamp != 0 && !no_time) time_stamp = stamp + MAC_TIMEOFFSET;
-
- (void)get_byte(); /* Ignore extra flags for the moment */
- (void)get_byte(); /* Ignore OS type for the moment */
-
- if ((flags & CONTINUATION) != 0)
- {
- unsigned part = (unsigned)get_byte();
- part |= ((unsigned)get_byte())<<8;
- }
-
- if ((flags & EXTRA_FIELD) != 0)
- {
- unsigned len = (unsigned)get_byte();
- len |= ((unsigned)get_byte())<<8;
- while (len--) (void)get_byte();
- }
-
- /* Get original file name if it was truncated */
-
- if ((flags & ORIG_NAME) != 0)
- {
- if (no_name || part_nb > 1)
- {
- /* Discard the old name */
- char c; /* dummy used for NeXTstep 3.0 cc optimizer bug */
- do {c=get_byte();} while (c != 0);
- }
- else
- {
- char *p = ofname;
- char *base = p;
- for (;;)
- {
- *p = (char)get_char();
- if (*p++ == '\0') break;
- if (p >= ofname+sizeof(ofname))
- {
- error("corrupted input -- file name too large");
- }
- }
- /* If necessary, adapt the name to local OS conventions: */
-
- MAKE_LEGAL_NAME(base);
-
- /*
- * it still can be too long, and is is a MacBinary file,
- * it won't be the actual name, either
- */
-
- if (base) list=0; /* avoid warning about unused variable */
- } /* no_name || to_stdout */
- } /* ORIG_NAME */
-
- /* Discard file comment if any */
- if ((flags & COMMENT) != 0)
- {
- while (get_char() != 0) /* null */ ;
- }
-
- if (part_nb == 1)
- {
- header_bytes = inptr + 2*sizeof(long); /* include crc and size */
- }
-
- }
- else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2
- && memcmp((char*)inbuf, PKZIP_MAGIC, 4) == 0)
- {
- /* To simplify the code, we support a zip file when alone only.
- * We are thus guaranteed that the entire local header fits in inbuf.
- */
- inptr = 0;
- work = unzip;
- if (check_zipfile(in) != OK) return -1;
- /* check_zipfile may get ofname from the local header */
- last_member = 1;
-
- }
- else if (memcmp(magic, PACK_MAGIC, 2) == 0)
- {
- work = unpack;
- method = PACKED;
- }
- else if (memcmp(magic, LZW_MAGIC, 2) == 0)
- {
- work = unlzw;
- method = COMPRESSED;
- last_member = 1;
- }
- else if (memcmp(magic, LZH_MAGIC, 2) == 0)
- {
- work = unlzh;
- method = LZHED;
- last_member = 1;
- }
- else if (force && to_stdout && !list)
- { /* pass input unchanged */
- method = STORED;
- work = copy;
- inptr = 0;
- last_member = 1;
- }
- if (method >= 0) return method;
-
- if (part_nb == 1)
- {
- DoError(INPUT_ERR,WARN_ERR, "%s: %s: not in gzip format", progname, ifname);
- exit_code = ERROR;
- return -1;
- }
- else
- {
- WARN((stderr, "%s: %s: decompression OK, trailing garbage ignored",
- progname, ifname));
- return -2;
- }
- }
-
-
-
- /* ========================================================================
- * Shorten the given name by one character, or replace a .tar extension
- * with .tgz. Truncate the last part of the name which is longer than
- * MIN_PART characters: 1234.678.012.gz -> 123.678.012.gz. If the name
- * has only parts shorter than MIN_PART truncate the longest part.
- * For decompression, just remove the last character of the name.
- *
- * IN assertion: for compression, the suffix of the given name is z_suffix.
- */
- local void shorten_name(name)
- char *name;
- {
- int len; /* length of name without z_suffix */
- char *trunc = NULL; /* character to be truncated */
- int plen; /* current part length */
- int min_part = MIN_PART; /* current minimum part length */
- char *p;
-
- len = strlen(name);
- if (decompress) {
- if (len <= 1) error("name too short");
- name[len-1] = '\0';
- return;
- }
- p = get_suffix(name);
- if (p == NULL) error("can't recover suffix");
- *p = '\0';
- save_orig_name = 1;
-
- /* compress 1234567890.tar to 1234567890.tgz */
- if (len > 4 && strequ(p-4, ".tar")) {
- strcpy(p-4, ".tgz");
- return;
- }
- /* Try keeping short extensions intact:
- * 1234.678.012.gz -> 123.678.012.gz
- */
- do {
- p = strrchr(name, PATH_SEP);
- p = p ? p+1 : name;
- while (*p) {
- plen = strcspn(p, PART_SEP);
- p += plen;
- if (plen > min_part) trunc = p-1;
- if (*p) p++;
- }
- } while (trunc == NULL && --min_part != 0);
-
- if (trunc != NULL) {
- do {
- trunc[0] = trunc[1];
- } while (*trunc++);
- trunc--;
- } else {
- trunc = strrchr(name, PART_SEP[0]);
- if (trunc == NULL) error("internal error in shorten_name");
- if (trunc[1] == '\0') trunc--; /* force truncation */
- }
- strcpy(trunc, z_suffix);
- }
-
- /* ========================================================================
- * If compressing to a file, check if ofname is not ambiguous
- * because the operating system truncates names. Otherwise, generate
- * a new ofname and save the original name in the compressed file.
- * If the compressed file already exists, ask for confirmation.
- * The check for name truncation is made dynamically, because different
- * file systems on the same OS might use different truncation rules (on SVR4
- * s5 truncates to 14 chars and ufs does not truncate).
- * This function returns -1 if the file must be skipped, and
- * updates save_orig_name if necessary.
- * IN assertions: save_orig_name is already set if ofname has been
- * already truncated because of NO_MULTIPLE_DOTS. The input file has
- * already been open and istat is set.
- */
-
- /*
- * MacGzip
- *
- * IN:
- * ofname generated/extracted from .gz
- * ofs = ifs
- */
- #define MAXPATHLEN 31
-
- local int check_ofname()
- {
- errno = 0;
- while ( strlen( ofname ) > MAXPATHLEN)
- shorten_name(ofname);
-
- CStrToStr255( ofs.name, ofname );
-
- if ( !decompress )
- {
- if ( noErr != (err = MakeOFSSpec( &ofs, "\pSave gzip file:" )))
- {
- exit_code = ERROR;
- return ERROR;
- }
- }
- return OK;
- }
-
-
- /* ========================================================================
- * Set the access and modification times from the given stat buffer.
- */
- local void reset_times (FSSpec *fs, struct stat *statb)
- {
- CInfoPBRec info;
-
- info.hFileInfo.ioNamePtr = fs->name;
- info.hFileInfo.ioVRefNum = fs->vRefNum;
- info.hFileInfo.ioFDirIndex = 0;
- info.hFileInfo.ioDirID = fs->parID;
-
-
- if ( noErr != ( err = PBGetCatInfo( (CInfoPBPtr) &info, false ) ) )
- {
- errno = err;
- }
- else
- {
- info.hFileInfo.ioNamePtr = fs->name;
- info.hFileInfo.ioVRefNum = fs->vRefNum;
- info.hFileInfo.ioFDirIndex = 0;
- info.hFileInfo.ioDirID = fs->parID;
-
- info.hFileInfo.ioFlCrDat = statb->st_ctime;
- info.hFileInfo.ioFlMdDat = statb->st_mtime;
-
- err = errno = PBSetCatInfo( (CInfoPBPtr) &info, false );
-
- }
- }
-
-
-
- /* ========================================================================
- * Copy modes, times, ownership from input file to output file.
- * IN assertion: to_stdout is false.
- */
- local void copy_stat(ifstat)
- struct stat *ifstat;
- {
- if (decompress && time_stamp != 0 && ifstat->st_mtime != time_stamp)
- {
- /* buf->st_atime = info->hFileInfo.ioFlMdDat;
- * buf->st_mtime = info->hFileInfo.ioFlMdDat;
- * buf->st_ctime = info->hFileInfo.ioFlCrDat;
- */
- ifstat->st_mtime =
- ifstat->st_atime =
- ifstat->st_ctime = time_stamp;
-
- }
- reset_times( &ofs, ifstat);
-
-
- remove_ofname = 0;
- /* It's now safe to remove the input file: */
-
- if ( !gPrefs.Misc.KeepOriginal )
- if ( fs_unlink(&ifs))
- {
- DoError(STDC_ERR, WARN_ERR, "Can't delete %s", ifname);
- }
- }
-
-
- /* ========================================================================
- * Free all dynamically allocated variables and exit with the given code.
- */
- local void do_exit(exitcode)
- int exitcode;
- {
-
- FREE(inbuf);
- FREE(outbuf);
- FREE(d_buf);
- FREE(window);
- #ifndef MAXSEG_64K
- FREE(tab_prefix);
- #else
- FREE(tab_prefix0);
- FREE(tab_prefix1);
- #endif
- if (exitcode==0)
- {
- return;
- }
- else
- {
- err = errno = noErr;
-
- longjmp( env, exitcode );
- /* this is not executed */
- DoError(PROG_ERR, QUIT_ERR, "Serious fail, quitting… (%d)", exitcode );
- }
- }
-
- /* ========================================================================
- * Signal and error handler.
- */
- RETSIGTYPE abort_gzip()
- {
- if (fd_busy[ifd] == 1)
- {
- close(ifd);
- }
-
- if ((remove_ofname) && (fd_busy[ofd] == 1))
- {
- close(ofd);
-
- if ( fd_table[ofd].new == 1 )
- fs_unlink (&ofs);
- }
- do_exit(ERROR);
- }
-
- /* ========================================================================
- * init the options
- *
- * Input:
- * - gPrefs
- * - ifs
- * - startup keys (in gApp.KeysMode and KeysOp)
- * - Op ( from expand to, compress to)
- */
-
- #define kAskRFID 154
- #define kAskRF_mb 1
- #define kAskRF_not 2
- #define kAskRF_quit 3
-
- local Boolean init_globals( FSSpec *fs )
- {
- /* decompress (-d) */
- /*
- * this can be set by:
- * dropping with 'opt' => force compress
- * dropping with 'ctrl' => force decompress
- * or
- * Menu 'Expand'/'Compress' -> Op ( keys already have modify this )
- * else
- * File type is 'Gzip' (or similar) / or DefaultCompress
- */
- Boolean error = FALSE;
-
- switch ( gApp.Op )
- {
- case kMisc_gzip:
- decompress = 0;
- break;
-
- case kMisc_gunzip:
- decompress = 1;
- break;
-
- case kMisc_auto:
-
-
- decompress=
- (( gPrefs.Misc.DefaultOp == kMisc_gunzip ) ||
- (
- ( gPrefs.Misc.DefaultOp == kMisc_auto ) &&
- (
- (gSufMap.Type == 'Gzip') ||
- (gSufMap.Type == 'ZIVU') ||
- (gSufMap.Type == 'ZIVM') ||
- (gSufMap.Type == 'pZIP')
- )
- ));
-
- break;
-
- default:
- DoError(PROG_ERR, QUIT_ERR, "there is a bug somewhere...");
- break;
- }
-
- force = gPrefs.gzip.Force; /* don't ask questions, compress links (-f) */
-
-
- no_name = -1; /* don't save or restore the original file name */
- no_time = -1; /* don't save or restore the original file time */
-
- if ( gPrefs.gzip.NoName )
- no_name = no_time = 1;
-
- if ( gPrefs.gzip.Name )
- no_name = no_time = 0;
-
- verbose = 0; /* be verbose (-v) */
- quiet = 0; /* be very quiet (-q) */
- maxbits = BITS; /* max bits per code for LZW */
- method = DEFLATED;/* compression method */
-
- level = (int) gPrefs.gzip.Level; /* compression level */
-
-
- exit_code = OK; /* program exit code */
- total_in = 0; /* input bytes for all files */
- total_out = 0; /* output bytes for all files */
- remove_ofname = 0; /* remove output file on error */
- work = zip;
-
-
- if (( gPrefs.gzip.UseCustomSuffix ) && ( decompress || (!decompress && !gPrefs.gzip.GunzipSuffix)))
- {
- Str255ToCStr( z_suffix, gPrefs.gzip.Suffix );
- }
- else
- {
- strncpy(z_suffix, Z_SUFFIX, sizeof(z_suffix)-1);
- }
- z_len = strlen(z_suffix);
-
- if ( !decompress )
- {
- Boolean IsText = ( gSufMap.Type == 'TEXT' );
-
- ascii = -1; /* -1 for unknown */
- macbinary = 0; /* still not declared OJO */
-
- if (( gPrefs.Compress.Keys ) && ( gApp.KeysMode != 0 ))
- {
- switch ( gApp.KeysMode )
- {
- case kAppKeyASCII:
- ascii = 1;
- macbinary = 0;
- break;
- case kAppKeyBin:
- ascii = 0;
- macbinary = 0;
- break;
- case kAppKeyMBin:
- ascii = 0;
- macbinary = 1;
- break;
- default:
- DoError(PROG_ERR,WARN_ERR,"Mala suerte, error del programador");
- break;
- }
- }
- else
- {
- if ( gPrefs.Compress.IC )
- {
- if ( gPrefs.Compress.IC_ASCII && IsText )
- {
- macbinary = 0;
- ascii = 1;
- }
- else
- {
- ResolveFileType( fs, nil, &gSufMap, kRFTUpload | kRFTFromSpec | kRFTIC );
-
- if ( gSufMap.Found )
- {
- if ( gSufMap.MacFile && !gPrefs.Compress.IC_NotMB )
- {
- ascii = 0;
- macbinary = 1;
- }
- else
- {
- ascii = !gSufMap.Binary;
- macbinary = 0;
- }
- if ( IsText && gPrefs.Compress.IC_ASCII )
- {
- ascii = 1;
- macbinary = 0;
- }
- }
- }
- }
- }
-
- if ( ascii == -1 ) /* still unresolved */
- {
- switch ( gPrefs.Compress.Mode )
- {
- case kComp_MASCII:
- ascii = 1;
- macbinary = 0;
- break;
- case kComp_MBin:
- ascii = 0;
- macbinary = 0;
- break;
- case kComp_MMB:
- ascii = 0;
- macbinary = 1;
- break;
- }
-
- if ( (ascii == 0) && IsText && ( macbinary == 0 ) && ( gPrefs.Compress.Mode_a ) )
- {
- ascii = 1;
- macbinary = 0;
- }
- }
-
- if (( macbinary == 0 ) && ( istat.st_rsize != 0 ))
- {
- switch ( gPrefs.Compress.ResFork )
- {
- case kComp_RFAsk:
- DoNotification();
- ParamText(fs->name,"\p","\p","\p");
- switch ( CautionAlert( kAskRFID, nil ) )
- {
- case kAskRF_mb:
- macbinary = 1;
- break;
- case kAskRF_not:
- break;
- case kAskRF_quit:
- error = TRUE;
- break;
- default:
- DoError(PROG_ERR,WARN_ERR,"Mala suerte, error del programador");
- break;
- }
- break;
- case kComp_RFMB:
- macbinary = 1;
- break;
- case kComp_RFNot:
- break;
- case kComp_RFQuit:
- error = TRUE;
- break;
-
- default:
- break;
- }
- }
- }
- else /* decompress */
- {
- ascii = macbinary = -1;
-
- /* we have no clue about output file */
- }
- return error;
- }
- /* ========================================================================
- * Prompt for destination (compressed file)
- *
- */
-
- OSErr PromptGZIPFile( FSSpec *fs, Str255 prompt )
- {
- OSErr result = noErr;
- StandardFileReply sfr;
-
- /* since this can be called from MacIO, after making some
- * processing, we need to post a notification
- */
-
- DoNotification( );
- StandardPutFile(prompt, fs->name, &sfr );
-
-
- if ( sfr.sfReplacing )
- {
- if ( 0 == memcmp( &ifs, &sfr.sfFile , sizeof(FSSpec) ) )
- {
- /* is this possible? */
- Str255ToCStr( ofname, sfr.sfFile.name );
- DoError(INPUT_ERR, WARN_ERR, "%s: cannot make %s onto itself",
- progname, ofname);
- return -1;
- }
- else
- {
- if (noErr != (err = FSpDelete(&sfr.sfFile)))
- {
- Str255ToCStr( ofname, sfr.sfFile.name );
- DoError(SYS_ERR, WARN_ERR, "Can't delete %s", ofname);
- return err;
- }
- else
- {
- *fs = sfr.sfFile;
- }
- }
- }
- else if ( sfr.sfGood )
- {
- Str255ToCStr( ofname, sfr.sfFile.name );
- *fs = sfr.sfFile;
- }
- else
- {
- result = -1;
- }
-
- return result;
- }
-
- OSErr MakeOFSSpec( FSSpec *fs , Str255 prompt )
- {
- StandardFileReply sfr;
- Boolean done;
-
- FSSpec fSpec;
- Boolean changedFlag;
-
- struct stat fldrStat;
-
-
- done = TRUE;
-
- if ( gApp.Prompt )
- {
- if ( noErr != ( err = PromptGZIPFile( fs, prompt )) )
- return err;
- }
- else if ( gPrefs.Folder.UseDestFolder && ( nil != gApp.DFolder ))
- {
- if( noErr == (err = ResolveAlias(nil, gApp.DFolder, &fSpec, &changedFlag)))
- {
- err = fs_stat( &fSpec, &fldrStat );
- if (( S_ISDIR ( fldrStat.st_mode ) ) && ( noErr == err ))
- {
- fs->vRefNum = fldrStat.st_dev;
- fs->parID = fldrStat.st_ino;
- }
- }
-
- if (noErr != err)
- {
- /* display alert and prompt for new destination */
- /* unset use folder too */
-
- DoError( SYS_ERR, WARN_ERR, "Sorry, Can't find your destination folder");
- gPrefs.Folder.UseDestFolder = FALSE;
-
- if ( noErr != PromptGZIPFile( fs, prompt ) )
- return err;
- }
- else
- {
- done = FALSE;
- }
-
- }
- else
- done = FALSE;
-
- if ( !done )
- {
- /* replace if force, else prompt */
- FInfo foo;
-
- err = FSpGetFInfo ( fs, &foo );
-
- if ( err != fnfErr )
- {
- if( err != noErr )
- {
- return err;
- }
- /* ofs exists */
- else if ( gPrefs.gzip.Force )
- {
- if (noErr != (err = FSpDelete(&sfr.sfFile)))
- {
- Str255ToCStr( ofname, sfr.sfFile.name );
- DoError(SYS_ERR, WARN_ERR, "Can't delete %s", ofname);
- return err;
- }
- }
- else
- {
- if ( noErr != (err = PromptGZIPFile( fs, prompt )) )
- {
- return err;
- }
- }
- }
- }
-
- return noErr;
- }
-
-